/* 
 * File:   GRPOperator.cpp
 * Author: beatriz
 * 
 * Created on 30 de Agosto de 2013, 15:37
 */

#include "GRPOperator.h"
#include "Problem.h"
#include "GRPCodification.h"
#include "oCrossover.h"
#include "oMutation.h"
#include "oInitializer.h"

#include <cstdlib>

#define GENES        3
#define SIGMA        1.0
#define PROBMUTA     0.25
#define ALPHA        0.25

const GRPOperator GRPOperator::obj;

GRPOperator::GRPOperator() {
}

GRPOperator::~GRPOperator() {
}

const char* GRPOperator::name()const {
    return "GRP-Operator";
}

class GRPOperator::INIT : public oInitializer {

    const char* name()const {
        return "GRP-init";
    }

    void initialize(Problem* prob, Codification* ind) throw (exception) {
        GRPCodification* codif = dynamic_cast<GRPCodification*> (ind);

        codif->cromo[0] = UniformRealDistribution::rand(0.1, 100); // x1 entre 0,1 e 100
        codif->cromo[1] = UniformRealDistribution::rand(0, 25.6); // x2 entre 0 e 25,6
        codif->cromo[2] = UniformRealDistribution::rand(0, 5); // x3 entre 0 e 5
    };
};

class GRPOperator::CROSS : public oCrossover {

    const char* name()const {
        return "GRP-cross-Heuristica";
    }

    /**
     * Crossover heurístico: c = p1 + r(p1-p2), onde p1 é melhor que p2, r ~ U(0,1).
     * @param prob
     * @param ind1 é a codificação do pai1. Obrigatoriamente ind1 deve ser melhor que ind2
     * @param ind2 é a codificação do pai2
     * @return 
     */
    Codification* crossover(Problem* prob, Codification* ind1, Codification* ind2) throw (exception) {
        GRPCodification* codif1 = dynamic_cast<GRPCodification*> (ind1);
        GRPCodification* codif2 = dynamic_cast<GRPCodification*> (ind2);
        GRPCodification* child = dynamic_cast<GRPCodification*> (codif1->New(prob));
        double r = UniformRealDistribution::rand(0, 1);
        for (int i = 0; i < GENES; i++) {
            child->cromo[i] = codif1->cromo[i] + r * (codif1->cromo[i] - codif2->cromo[i]);
        }

        if (child->cromo[0] > 100.0)
            child->cromo[0] = 100.0;
        if (child->cromo[0] < 0.1)
            child->cromo[0] = 0.1;
        if (child->cromo[1] > 25.6)
            child->cromo[1] = 25.6;
        if (child->cromo[1] < 0.0)
            child->cromo[1] = 0;
        if (child->cromo[2] > 5.0)
            child->cromo[2] = 5.0;
        if (child->cromo[2] < 0.0)
            child->cromo[2] = 0.0;

        return child;
    };
};

class GRPOperator::CROSS2 : public oCrossover {

    const char* name() const {
        return "GRP-cross-BLXalpha";
    }

    /**
     * Crossover BLXalpha com Beta diferente para cada gene
     * @param prob
     * @param ind1 codificação do pai1
     * @param ind2 codificaçao do pai2
     * @return 
     */
    Codification* crossover(Problem* prob, Codification* ind1, Codification* ind2) throw (exception) {
        GRPCodification* codif1 = dynamic_cast<GRPCodification*> (ind1);
        GRPCodification* codif2 = dynamic_cast<GRPCodification*> (ind2);
        GRPCodification* child = dynamic_cast<GRPCodification*> (codif1->New(prob));
        for (int i = 0; i < GENES; i++) {
            child->cromo[i] = codif1->cromo[i] + UniformRealDistribution::rand(-ALPHA, 1 + ALPHA)*(codif2->cromo[i] - codif1->cromo[i]);
        }

        if (child->cromo[0] > 100.0)
            child->cromo[0] = 100.0;
        if (child->cromo[0] < 0.1)
            child->cromo[0] = 0.1;
        if (child->cromo[1] > 25.6)
            child->cromo[1] = 25.6;
        if (child->cromo[1] < 0.0)
            child->cromo[1] = 0;
        if (child->cromo[2] > 5.0)
            child->cromo[2] = 5.0;
        if (child->cromo[2] < 0.0)
            child->cromo[2] = 0.0;

        return child;
    };

};

class GRPOperator::MUT : public oMutation {

    const char* name()const {
        return "GRP-mut-gaussiana";
    }

    void mutation(Problem* prob, Codification* ind) throw (exception) {
        GRPCodification* codif = dynamic_cast<GRPCodification*> (ind);

        if (UniformRealDistribution::rand(0, 1) < PROBMUTA) {
            int gene = UniformIntDistribution::rand(0, GENES - 1);
            codif->cromo[gene] = GaussianDistribution::rand(codif->cromo[gene], SIGMA);
        }

        if (codif->cromo[0] > 100.0)
            codif->cromo[0] = 100.0;
        if (codif->cromo[0] < 0.1)
            codif->cromo[0] = 0.1;
        if (codif->cromo[1] > 25.6)
            codif->cromo[1] = 25.6;
        if (codif->cromo[1] < 0.0)
            codif->cromo[1] = 0;
        if (codif->cromo[2] > 5.0)
            codif->cromo[2] = 5.0;
        if (codif->cromo[2] < 0.0)
            codif->cromo[2] = 0.0;
    };
};

Node* GRPOperator::NewService(int index)const {
    switch (index) {
        case 0: return new INIT();
        case 1: return new CROSS2();
        case 2: return new MUT();
        case 3: return new CROSS();
    }
    return NULL;
}
